package com.exp.security.config.captcha;

import com.exp.security.config.MyAuthenticationFailureHandler;
import com.exp.security.constant.AppConstants;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.filter.GenericFilterBean;

import java.io.IOException;

/**
 * @author zhangxj
 * @date 2025/1/7
 * @Description 验证码校验过滤器
 */
public class CaptchaAuthenticationFilter extends GenericFilterBean {
    // 请求匹配器
    private static final AntPathRequestMatcher LOGIN_REQUEST_MATCHER = new AntPathRequestMatcher("/login", "POST");
    // 验证码参数名
    public static final String FORM_CAPTCHA_KEY = "captcha";
    // 验证码ID参数名
    public static final String FORM_CAPTCHA_ID_KEY = "captchaId";

    /**
     * 自定义的认证失败处理器
     */
    private final MyAuthenticationFailureHandler failureHandler;
    /**
     * redisTemplate
     */
    private final StringRedisTemplate stringRedisTemplate;

    public CaptchaAuthenticationFilter(MyAuthenticationFailureHandler failureHandler, StringRedisTemplate stringRedisTemplate) {
        this.failureHandler = failureHandler;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (LOGIN_REQUEST_MATCHER.matches((HttpServletRequest) request)) {
            // login 请求时，执行验证码校验
            try {
                // 获取请求参数
                String captcha = request.getParameter(FORM_CAPTCHA_KEY);
                String captchaId = request.getParameter(FORM_CAPTCHA_ID_KEY);
                if (StringUtils.isBlank(captcha) || StringUtils.isBlank(captchaId)) {
                    throw new CaptchaAuthenticationException("验证码参数为空");
                }
                String cacheCaptcha = stringRedisTemplate.opsForValue().get(AppConstants.CAPTCHA_PREFIX + captchaId);
                if (StringUtils.isBlank(cacheCaptcha)) {
                    throw new CaptchaAuthenticationException("验证码已过期");
                }
                if (!cacheCaptcha.equalsIgnoreCase(captcha)) {
                    throw new CaptchaAuthenticationException("验证码错误");
                }

                // 验证码校验通过，放行
                chain.doFilter(request, response);
            } catch (AuthenticationException e) {
                failureHandler.onAuthenticationFailure((HttpServletRequest) request, (HttpServletResponse) response, e);
            }
        } else {
            // 非 login 请求，直接放行
            chain.doFilter(request, response);
        }
    }
}
